//@author A0080917B

#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

using namespace std;

namespace ExtractParamsForKeywordsTest
{		
	TEST_CLASS(ExtractParamsForKeywordsUnitTests)
	{
	public:
		
		TEST_METHOD(NaturalOneKeywordOneParam)
		{
			vector<string> naturalKeywords;
			naturalKeywords.assign(NATURALKEYWORDSARRAY, NATURALKEYWORDSARRAY + NATURALKEYWORDSARRAYSIZE);

			string input = " on next Tuesday 1234";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> onParams;
			onParams.push_back("next Tuesday 1234");
			vector<string> fromParams;
			vector<string> toParams;
			vector<string> byParams;
			vector<string> inParams;
			expectedKeywordsAndParams.push_back(onParams);
			expectedKeywordsAndParams.push_back(fromParams);
			expectedKeywordsAndParams.push_back(toParams);
			expectedKeywordsAndParams.push_back(byParams);
			expectedKeywordsAndParams.push_back(inParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, naturalKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(NaturalTwoKeywordsMultipleParams)
		{
			vector<string> naturalKeywords;
			naturalKeywords.assign(NATURALKEYWORDSARRAY, NATURALKEYWORDSARRAY + NATURALKEYWORDSARRAYSIZE);

			string input = " on next Tuesday from 1234 to 2345 in blah blah from next Monday 0123 to next Wednesday 1230";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> onParams;
			onParams.push_back("next Tuesday");
			vector<string> fromParams;
			fromParams.push_back("1234");
			fromParams.push_back("next Monday 0123");
			vector<string> toParams;
			toParams.push_back("2345");
			toParams.push_back("next Wednesday 1230");
			vector<string> byParams;
			vector<string> inParams;
			inParams.push_back("blah blah");
			expectedKeywordsAndParams.push_back(onParams);
			expectedKeywordsAndParams.push_back(fromParams);
			expectedKeywordsAndParams.push_back(toParams);
			expectedKeywordsAndParams.push_back(byParams);
			expectedKeywordsAndParams.push_back(inParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, naturalKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}


			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(NaturalNoKeywords)
		{
			vector<string> naturalKeywords;
			naturalKeywords.assign(NATURALKEYWORDSARRAY, NATURALKEYWORDSARRAY + NATURALKEYWORDSARRAYSIZE);

			string input = "CS2103 post-lecture quiz";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> onParams;
			vector<string> fromParams;
			vector<string> toParams;
			vector<string> byParams;
			vector<string> inParams;
			expectedKeywordsAndParams.push_back(onParams);
			expectedKeywordsAndParams.push_back(fromParams);
			expectedKeywordsAndParams.push_back(toParams);
			expectedKeywordsAndParams.push_back(byParams);
			expectedKeywordsAndParams.push_back(inParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, naturalKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "CS2103 post-lecture quiz";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(NaturalThreeKeywordsOneParam)
		{
			vector<string> naturalKeywords;
			naturalKeywords.assign(NATURALKEYWORDSARRAY, NATURALKEYWORDSARRAY + NATURALKEYWORDSARRAYSIZE);

			string input = "dinner with mum on next Tuesday 1200 in Ritz Carlton";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> onParams;
			onParams.push_back("next Tuesday 1200");
			vector<string> fromParams;
			vector<string> toParams;
			vector<string> byParams;
			vector<string> inParams;
			inParams.push_back("Ritz Carlton");
			expectedKeywordsAndParams.push_back(onParams);
			expectedKeywordsAndParams.push_back(fromParams);
			expectedKeywordsAndParams.push_back(toParams);
			expectedKeywordsAndParams.push_back(byParams);
			expectedKeywordsAndParams.push_back(inParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, naturalKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "dinner with mum";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}
		
		TEST_METHOD(AttributeOneKeywordOneParam)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = " .d Dinner with mum";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			dParams.push_back("Dinner with mum");
			vector<string> sParams;
			vector<string> eParams;
			vector<string> lParams;
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(AttributeTwoKeywordsMultipleParams)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = " .s next Tuesday 1200 .d testing repeated attributes error .s this Tuesday 1200";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			dParams.push_back("testing repeated attributes error");
			vector<string> sParams;
			sParams.push_back("next Tuesday 1200");
			sParams.push_back("this Tuesday 1200");
			vector<string> eParams;
			vector<string> lParams;
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(AttributeFourKeywordsMultipleParams)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = " .d Dinner with mum .s next Tuesday 1200 .e next Tuesday 1400 .l Ritz Carlton .e next Monday 1234";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			dParams.push_back("Dinner with mum");
			vector<string> sParams;
			sParams.push_back("next Tuesday 1200");
			vector<string> eParams;
			eParams.push_back("next Tuesday 1400");
			eParams.push_back("next Monday 1234");
			vector<string> lParams;
			lParams.push_back("Ritz Carlton");
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(AttributeKeywordWithoutParam)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = " .d .s next Tuesday 1200 .e next Tuesday 1400 .l Ritz Carlton .l International restaurant";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			dParams.push_back("");
			vector<string> sParams;
			sParams.push_back("next Tuesday 1200");
			vector<string> eParams;
			eParams.push_back("next Tuesday 1400");
			vector<string> lParams;
			lParams.push_back("Ritz Carlton");
			lParams.push_back("International restaurant");
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(AttributeWithParamWithoutKeyword)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = "testing param without recognised keyword .d lunch with mum .s next Tuesday 1200 .e next Tuesday 1400 .l Ritz Carlton .d and dad";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			dParams.push_back("lunch with mum");
			dParams.push_back("and dad");
			vector<string> sParams;
			sParams.push_back("next Tuesday 1200");
			vector<string> eParams;
			eParams.push_back("next Tuesday 1400");
			vector<string> lParams;
			lParams.push_back("Ritz Carlton");
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = "testing param without recognised keyword";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

		TEST_METHOD(NoRecognisedAttribute)
		{
			vector<string> attributeKeywords;
			vector<vector<string>> attributeKeywordsAndParams;
			attributeKeywords.assign(ATTRIBUTEKEYWORDSARRAY, ATTRIBUTEKEYWORDSARRAY + ATTRIBUTEKEYWORDSARRAYSIZE);

			string input = ".desc testing invalid attribute keyword .loc test location";
			vector<vector<string>> expectedKeywordsAndParams;
			vector<string> dParams;
			vector<string> sParams;
			vector<string> eParams;
			vector<string> lParams;
			expectedKeywordsAndParams.push_back(dParams);
			expectedKeywordsAndParams.push_back(sParams);
			expectedKeywordsAndParams.push_back(eParams);
			expectedKeywordsAndParams.push_back(lParams);

			std::string todoFileName = "testingTodo.txt";
			std::string doneFileName = "testingDone.txt";
			Manipulator* todoTMPtr;
			todoTMPtr = new TextManipulator(todoFileName);
			Manipulator* doneTMPtr;
			doneTMPtr = new TextManipulator(doneFileName);
			TestMethods test(todoTMPtr, doneTMPtr);
			
			try {
				vector<vector<string>> keywordsAndParams;
				keywordsAndParams = test.executeExtractParamsForKeywords(input, attributeKeywords);

				Assert::AreEqual(expectedKeywordsAndParams.size(), keywordsAndParams.size());

				for(unsigned int i = 0 ; i < keywordsAndParams.size() ; i++) {
					Assert::AreEqual(expectedKeywordsAndParams[i].size(), keywordsAndParams[i].size());
					for(unsigned int j = 0 ; (!keywordsAndParams.empty()) && (j < keywordsAndParams[i].size()) ; j++) {
						Assert::AreEqual(expectedKeywordsAndParams[i][j], keywordsAndParams[i][j]);
					}
				}

				string expectedRemainingInput = ".desc testing invalid attribute keyword .loc test location";
				Assert::AreEqual(expectedRemainingInput, input);
			} catch(exception& exception) {
				std::string expectedError = "";
				std::string errorFeedback;
				errorFeedback = exception.what();
				Assert::AreEqual(expectedError, errorFeedback);
			}

			delete todoTMPtr;
			delete doneTMPtr;
		}

	};
}